package midas.mw.crt.jxta;

import midas.mw.cfg.CfgError;
import midas.mw.cfg.CfgLogging;
import midas.mw.cfg.log.Logger;
import midas.mw.cfg.mwmonitor.MWMonitor;
import midas.mw.crt.Constants;
import midas.mw.crt.CrtImpl;
import midas.mw.crt.CrtException;
import midas.mw.crt.SearchThread;
import midas.mw.crt.common.IPMessage;
import midas.mw.crt.presence.NodePresence;
import midas.mw.crt.presence.PresenceAdv;
import midas.mw.crt.presence.PresenceKey;
import midas.mw.crt.presence.PresenceListener;

import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.pipe.OutputPipe;
import net.jxta.platform.ModuleSpecID;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.ModuleImplAdvertisement;
import net.jxta.protocol.PeerAdvertisement;
import net.jxta.protocol.PeerGroupAdvertisement;
import net.jxta.protocol.RdvAdvertisement;
import net.jxta.discovery.DiscoveryService;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.rendezvous.RendezvousEvent;
import net.jxta.rendezvous.RendezvousListener;
import net.jxta.document.Advertisement;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.Element;
import net.jxta.endpoint.ByteArrayMessageElement;
import net.jxta.endpoint.EndpointAddress;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.Messenger;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.exception.PeerGroupException;
import net.jxta.membership.Authenticator;
import net.jxta.membership.MembershipService;
import net.jxta.credential.AuthenticationCredential;
import net.jxta.peer.PeerID;
import net.jxta.id.ID;
import net.jxta.id.IDFactory;
import net.jxta.impl.protocol.PipeAdv;
import net.jxta.impl.rendezvous.RendezVousServiceImpl;
import net.jxta.impl.rendezvous.RendezVousServiceInterface;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileOutputStream;

import java.net.URI;
import java.net.URISyntaxException;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.HashMap;

/**
 * This class manages the JXTA module of the CRT
 */
public class JxtaModule implements PresenceListener, Runnable, RendezvousListener
{		
	/**
     * Handle to the MIDAS peer group discovery service
     */
	protected DiscoveryService midasDiscovery	= null;
	
	/**
	 * This property list stores the information about some JXTA features
	 */
    protected Properties configuration 			= null;
    
    /**
	 * Name of the file storing the parameters to initiate the JXTA module
	 * properly
	 */
    private String CONFIGURATION_FILE  			= null;
    
    /**
     * This variable is included to manage different JXTA versions
     */
    protected Configuration JXTAversionSpecific = null;
    
    private NetworkManager networkManager		= null;
    
    /**
     * MIDAS group. MIDAS will instantiate its own peer group using the Network
     * Peer Group as a base
     */
    protected PeerGroup midas					= null;
        
    /**
     * Unique identifier of the rendezvous service for the MIDAS group
     */
    protected String midasRendezvousServiceID	= null;
    
    /**
     * Variable setting if the JXTA module must go on running or not
     */
    private boolean terminateThread				= true;
    
    /**
     * Variable setting if the JXTA is started or not
     */
    private boolean started				        = false;
        
    /**
	 * Instance of the CRT running in the node
	 */
    protected CrtImpl crt;
    
    /**
     * Number of retries of a user node to connect to a Central Node 
     */
    private int numRetries 						= 3;
    
    /**
     * MIDAS identifier of the Central Node to which is connected
     */
    private String centralNodeId 				= null;
    
    /**
     * JXTA unique identifier of the Central Node to which is connected
     */
    private String centralNodeJXTAId 			= null;
    
    /**
     * Manages the node presence functionality
     */
    private NodePresence nodePresence 			= null;
    
    
    private final Object outputPipeLock = new String("OutputPipeLock");
    
    /**
     * Default constructor
     */
	public JxtaModule ()
    {
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule()");			
    }
	
	/**
	 * Constructor - initiate local variables
	 * @param crt Instance of the CRT running in the node
	 */
    public JxtaModule (CrtImpl crt)
    {
    	CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule(CrtImpl)");
    	
    	this.crt = crt;
    }
    
    /**
	 * Sets the instance of the CRT running in the node
     * @param crt Instance of the CRT running in the node
     */
    public void setCrt(CrtImpl crt)
    {
    	CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.setCrt(CrtImpl)");
    	
    	this.crt = crt;
    }
	
    //CONFIGURE AND START JXTA MODULE//////////////////////
    /**
     * Configures the JXTA module with the parameters specified in the 
     * configuration file
     * 
     * @throws CrtException If the JXTA module can not be configured
     */
	public void configurePlatform() throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.configurePlatform()");				
		
			
		//Loading the configuration information
		if (System.getProperty("JXTA_HOME") == null)		
			System.setProperty("JXTA_HOME", "data" + System.getProperty("file.separator") + "crt");					
		
		CONFIGURATION_FILE = "." + System.getProperty("file.separator") + "conf" + System.getProperty("file.separator") + "peerconfig" + System.getProperty("file.separator") + "datospeer.txt";
				
		loadConfiguration();		
		String nodeId  	 		= crt.getConstants().getNodeId();
		String principal 		= getConfPeerCredential();
		String password  		= getConfPeerPassword();
		String publicIPAddress 	= crt.getConstants().getPublicIPAddress();
		//If there is a previous one, it will be used. If not, a new one will be 
		//generated automatically
		String peerId 		= getConfPeerID();
		
		if (peerId == null)
			peerId = generatePeerId();
		
		
		clearCache(new File(System.getProperty("JXTA_HOME"), "cm"));
		
		try 
		{
			//Depending on the configuration a different class could be used
			String usedClass 	= "midas.mw.crt.jxta.NodeConfiguration";
			if ((crt.getConstants().getNodeType() == crt.getConstants().CENTRAL_NODE) ||
					(crt.getConstants().getNodeType() == crt.getConstants().GATEWAY_NODE))
				usedClass = "midas.mw.crt.jxta.CentralNodeConfiguration";						
			
			JXTAversionSpecific = (Configuration)Class.forName(usedClass).newInstance();
			
		} catch (InstantiationException ie) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.configurePlatform(). Error instantianing a class: '" + 
					ie.getMessage() + "'", null);
			throw new CrtException();
		} catch (IllegalAccessException iae) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.configurePlatform(). Error accessing a class: '" + 
					iae.getMessage() + "'", null);
			throw new CrtException();
		} catch (ClassNotFoundException cnfe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.configurePlatform(). Class not found: '" + 
					cnfe.getMessage() + "'", null);
			throw new CrtException();
		}		
		
		//Instantiating the JXTA platform
		networkManager = JXTAversionSpecific.startJxta(nodeId, principal, password, peerId, publicIPAddress);
		
		try {
			//TheNetworkManager.startNetwork();
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, "Starting JXTA ...");						
	    	midas = networkManager.startNetwork();
	    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, "JXTA started...");				
			
	    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, "Peer name: "  + midas.getPeerName());
	    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, "Peer Group name: " + midas.getPeerGroupName());
	    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, "Peer Group ID: " + midas.getPeerID().toString());
	       
	    } catch (PeerGroupException pgex) {
	        // Cannot initialize peer group
	        pgex.printStackTrace();
	        //System.exit(-1);
	    } catch (IOException ioex) {
	        ioex.printStackTrace();
	        //System.exit(-1);
	    } catch (Exception e) {
	        e.printStackTrace();
	    }
	    
		
		if (midas == null)
			throw new CrtException();
		//Getting the discovery service from the default net peer group.
		//After instantiating the JXTAplatform we wait until we are connected to a rendezvous peer 
		//It would not be necessary to wait for a rendezvous connection if the application is running
		//locally on a subnet and communicating with other peers on that subnet via multicast. However,
		//in other configurations you might want to wait until a rendezvous connection is established
		midasDiscovery = midas.getDiscoveryService();
		
		//Cleaning the Network Peer Group cache
		//clearLocalCache(midasDiscovery);
	}
	
	private String generatePeerId () throws CrtException 
	{
		
		try {
			ID id = IDFactory.fromURI(new URI(Configuration.MIDAS_GROUP_ID));
			PeerGroupID pgId = IDFactory.newPeerGroupID((PeerGroupID)id);
			PeerID peerID = IDFactory.newPeerID(pgId);
			return peerID.toString();
		} catch (URISyntaxException use){
			use.printStackTrace();
			throw new CrtException();
		}

	}
	
	/**
	 * Starts the JXTA module
	 * @throws CrtException If the JXTA module can not be started
	 */
	public void startPlatform() throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.startPlatform()");
		
		if ((crt.getConstants().getNodeType() == crt.getConstants().CENTRAL_NODE) ||
				(crt.getConstants().getNodeType() == crt.getConstants().GATEWAY_NODE))
		{				
			//Configuring the RDV of the Network Peer Group
			//configureCentralNode(netPeerGroup.getRendezVousService());
						
			//Creating the MIDAS group
			//createGroup();
			
			//Configuring the CentralNode of the MIDAS Peer Group			
			//configureCentralNode(midas.getRendezVousService());
			
			//midasDiscovery = midas.getDiscoveryService();
			
			//Cleaning the MIDAS Peer Group cache
			//clearLocalCache(midasDiscovery);			
			
			//Add itself to listen to presence messages and ip messages			
			midas.getEndpointService().addIncomingMessageListener(crt.getPacketForwarder(), Constants.PRESENCE_SERVICE, midas.getPeerGroupID().toString());			
			midas.getEndpointService().addIncomingMessageListener(crt.getPacketForwarder(), Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());
		    
			//Add itself to listen to presence messages to the MIDAS group
			midas.getRendezVousService().addPropagateListener(Constants.BROADCAST_MESSAGE_SERVICE, midas.getPeerGroupID().toString(), crt.getPacketForwarder());
			
			//Adding itself as part of the MIDAS Group
			//getNetworkAddress(netPeerGroup.getPeerID(), midasDiscovery);
			
			//Setting identifier for rendezvous service for the MIDAS group
			midasRendezvousServiceID = getMidasRendezvousID();
			
			PresenceAdv presenceAdv = null;            
            presenceAdv = (PresenceAdv) AdvertisementFactory.newAdvertisement(PresenceAdv.getAdvertisementType());            
            presenceAdv.setPesenceNodeID(midas.getPeerID().toString());            
            presenceAdv.setNodeType(crt.getConstants().getNodeType());            
            presenceAdv.setPresenceName(crt.getNetworkManager().getOwnNodeId());            
            presenceAdv.setProxyName(centralNodeId);
          	nodePresence = new NodePresence(midas, this, presenceAdv);
          	
          	PresencePipe pp = new PresencePipe(this);
          	pp.start(midas);
          	
          	MessagePipe mp = new MessagePipe(this);
          	mp.start(midas);
          	//midas.getProxyService().addPresenceListener(nodePresence);
          	/*try {
          	netPeerGroup.getPipeService().createOutputPipe(mp.advertisement, this);
          	} catch (IOException ioe){
          		ioe.printStackTrace();
          	}*/
		}
		
		else
		{									
			//Add itself to listen to presence messages and ip messages
			midas.getEndpointService().addIncomingMessageListener(crt.getPacketForwarder(), Constants.PRESENCE_SERVICE, midas.getPeerGroupID().toString());				
			midas.getEndpointService().addIncomingMessageListener(crt.getPacketForwarder(), Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());
			
			//Add itself to listen to presence messages to the MIDAS group
			midas.getRendezVousService().addPropagateListener(Constants.BROADCAST_MESSAGE_SERVICE, midas.getPeerGroupID().toString(), crt.getPacketForwarder());				
			
			//Connecting to a rendezvous for the MIDAS Peer Group
			midas.getRendezVousService().addListener(this);
			
			boolean connected = networkManager.waitForRendezvousConnection(60000);
			
							
			if(!connected)
			{
				CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
						"JxtaModule.configurePlatform(). The edge is not connected to a Central Node for " +
						"the MIDAS Peer Group", null);	
				throw new CrtException();
			}	
			else
			{							
				while (centralNodeId == null)
				{
					try {
						Thread.currentThread().sleep(400);
					}catch (InterruptedException ie){}
					
					DiscoveryService ds = networkManager.getNetPeerGroup().getDiscoveryService();
			        
		        	try {
		        		Enumeration e = ds.getLocalAdvertisements(DiscoveryService.PEER, "PID", "urn:jxta:" + centralNodeJXTAId);
			        	
			        	PeerAdvertisement adv;
			    	    while (e.hasMoreElements()) 
			    	    {
			    	    	adv = (PeerAdvertisement)e.nextElement();
			    	    	centralNodeId = adv.getName();
			    	        crt.getNodeIdentifierSolver().put("urn:jxta:" + centralNodeJXTAId, centralNodeId, Constants.CENTRAL_NODE, null, "");				    	
			    	        break;
			    	    }
		        	} catch (IOException ioe){ioe.printStackTrace();}
				}
		    	
			}
			
			midasRendezvousServiceID = getMidasRendezvousID();
			
			PresenceAdv presenceAdv = null;
            presenceAdv = (PresenceAdv) AdvertisementFactory.newAdvertisement(PresenceAdv.getAdvertisementType());
            presenceAdv.setPesenceNodeID(midas.getPeerID().toString());	            
            presenceAdv.setNodeType(crt.getConstants().getNodeType());	
            presenceAdv.setPresenceName(crt.getNetworkManager().getOwnNodeId());
            presenceAdv.setProxyName(centralNodeId);
            nodePresence = new NodePresence(midas, this, presenceAdv);
		}	

		CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
				"JxtaModule.configurePlatform()." + 
				"\nMIDAS PEER GROUP: " +
				"\n\t" + midas.getPeerGroupID() +
				"\n\t" + midas.getPeerGroupName() + 
				"\n\t" + midas.getPeerGroupAdvertisement().getDescription());	
			
		CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
				"JxtaModule.configurePlatform()." +
				"\nPEER: " +
				"\n\t" + midas.getPeerName() +
				"\n\t" + midas.getPeerID());		

		setConfPeerID(midas.getPeerID().toString());
		saveConfiguration();
	}
	
	/**
	 * Loads the configuration form the specified file
	 * @throws CrtException If the configuration can not be loaded
	 */
	protected void loadConfiguration() throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.loadConfiguration()");				
		
		configuration = new Properties();
		try
		{
			//Checking if the file exists. If not, its created
			File f = new File(CONFIGURATION_FILE);
			if (!f.exists()) 
				CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,  
						"JxtaModule.loadConfiguration(). Creating file '" + f.getAbsolutePath() + "'");
			while (!f.exists())
			{					
				File dir1 = f.getParentFile();
				File dir2 = f.getParentFile();				
				while(dir1 != null && !dir1.exists())
				{					
					dir2 = dir1;
					dir1 = dir1.getParentFile();						
				}
				//The first existing directory is in dir2
				if(!dir2.exists()) 
					dir2.mkdir();
				else 
					f.createNewFile();
			}
			
			//Reading the configuration 
			FileInputStream input = new FileInputStream(CONFIGURATION_FILE); 
			configuration.load(input);
			
			if (!configuration.containsKey("PeerNombre"))		
				configuration.setProperty("PeerNombre", "Not Defined");
			if (!configuration.containsKey("PeerCredential"))	
				configuration.setProperty("PeerCredential", "midas");
			if (!configuration.containsKey("PeerPassword")) 	
				configuration.setProperty("PeerPassword", "midas");
			input.close();
			
			//Saving changes
			saveConfiguration();
			
		} catch(FileNotFoundException fnfe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.loadConfiguration(). Failed to get the Properties file: '" + 
					fnfe.getMessage() + "'", null);
	      	throw new CrtException ();
		} catch(IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.loadConfiguration(). Failed to read the Properties file: '" + 
					ioe.getMessage() + "'", null);
			throw new CrtException ();
		}
	}	
	
	/**
	 * Saves the configuration to the specified file
	 * @throws CrtException If the configuration can not be saved
	 */
	protected void saveConfiguration() throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.saveConfiguration()");
		
		FileOutputStream out;
		try {
			out = new FileOutputStream(CONFIGURATION_FILE);
			configuration.store(out, null);
			out.close();
		}
		catch (FileNotFoundException fnfe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.saveConfiguration(). An attempt to open the file to save configuration " +
					"has failed: '" + fnfe.getMessage() + "'", null);
			throw new CrtException();
		}
		catch (IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
					"JxtaModule.saveConfiguration(). An I/O exception of some sort has occurred saving " +
					"configuration: '" + ioe.getMessage() + "'", null);
			throw new CrtException();
		}

	}
	
	/**
	 * Shows if the JXTA module has been started
	 * @return The status of the JXTA module
	 */
	public boolean isStarted()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.isStarted()");
		
		return started;
	}

	/**
	 * Gets the MIDAS node identifier of the Central Node to which it is connected
	 * @return The MIDAS node identifier of the Central Node to which it is connected
	 */
	public String getCentralNodeId()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getCentralNodeId()");
		
		return centralNodeId;
	}
	
	/**
	 * Gets the JXTA unique identifier of the Central Node to which it is connected 
	 * @return The JXTA unique identifier of the Central Node to which it is connected
	 */
	public String getCentralNodePeerId()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getCentralNodePeerId()");
		
		return centralNodeJXTAId;
	}
	
	/**
	 * Sets the JXTA unique identifier
	 * 
	 * @param peerId JXTA unique identifier
	 */
	protected void setConfPeerID(String peerId)
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.setConfPeerID(" + peerId + ")");
					
		configuration.setProperty("PeerID", peerId);
	}
	
	/**
	 * Gets the JXTA unique identifier
	 * 
	 * @return The JXTA unique identifier
	 */
	protected String getConfPeerID()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getConfPeerID()");
		
		return (String)configuration.get("PeerID");
	}
	
	/**
	 * Returns the credential for security establishing and communicating 
	 * identity within JXTA
	 * 
	 * @return The credential for security establishing and communicating 
	 * 			identity within JXTA
	 */
	protected String getConfPeerCredential()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getConfPeerCredential()");
		
		return (String)configuration.get("PeerCredential");
	}
	
	/**
	 * Returns the password for the personal security environment
	 * 
	 * @return The password for the personal security environment
	 */
	protected String getConfPeerPassword()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getConfPeerPassword()");
		
		return (String)configuration.get("PeerPassword");
	}
	
	/**
	 * Stops the JXTA module
	 * @throws CrtException If the JXTA module can not be stopped
	 */
	public void stopJxtaModule() throws CrtException
	{		
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.stopJxtaModule()");
		
		terminateThread = true;
		if (started)
		{
		
			if (crt.getConstants().getNodeType() == crt.getConstants().USER_NODE)
			{
				/*if (netPeerGroup != null)
				{
					for (Enumeration en = netPeerGroup.getRendezVousService().getConnectedRendezVous(); en.hasMoreElements();)
						netPeerGroup.getRendezVousService().disconnectFromRendezVous((ID)en.nextElement());
					if(netPeerGroup.getRendezVousService().isConnectedToRendezVous())
					{
						synchronized (this)
						{
							try {
								wait(30000);
							} catch (InterruptedException ie){
								ie.printStackTrace();							
							}
						}
					}
					if(netPeerGroup.getRendezVousService().isConnectedToRendezVous())
					{
						CfgError.errorReporting(CfgError.ERR_OPER, "CRT.JxtaBaseModule", CfgError.SEV_FATAL, 
								"stopModule(). The edge can not disconnected from all Central Nodes for " +
								"the Network Peer Group", null);	
						throw new CrtException();
					}
				}*/
				if (midas != null)
				{
					//midas.getRendezVousService().removeListener(this);
					for (Enumeration en = midas.getRendezVousService().getConnectedRendezVous(); en.hasMoreElements();)
						midas.getRendezVousService().disconnectFromRendezVous((ID)en.nextElement());
					if(midas.getRendezVousService().isConnectedToRendezVous())
					{
						synchronized (this)
						{
							try {
								wait(30000);
							} catch (InterruptedException ie){
								ie.printStackTrace();							
							}
						}
					}
					if(midas.getRendezVousService().isConnectedToRendezVous())
					{
						CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
								"JxtaModule.stopModule(). The edge can not disconnected from all Central Nodes for " +
								"the MIDAS Peer Group", null);	
						throw new CrtException();
					}
					try {
						if (midas.getMembershipService() != null)
							midas.getMembershipService().resign();
					} catch (PeerGroupException pge) {
						CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
								"JxtaModule.stopModule(). The Membership Service for the MIDAS peer group can not " +
								"be obtained", null);
					}
				}
			}	
			else
				nodePresence.announceLeave(nodePresence.getLocalPresenceKey());
			try {
				if (midas.getMembershipService() != null)
					midas.getMembershipService().resign();
			} catch (PeerGroupException pge) {
				CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_FATAL, 
						"JxtaModule.stopModule(). The Membership Service for the MIDAS peer group can not " +
						"be obtained", null);
			}
			
			/*if (netPeerGroup!= null)
			{
				netPeerGroup.getRendezVousService().removeListener(this);
				
				netPeerGroup.stopApp();
				netPeerGroup.unref();
				netPeerGroup = null;
			}*/
			
			if (midas!= null)
			{
				//midas.getRendezVousService().removeListener(this);
				
				midas.stopApp();
				midas.unref();
				midas = null;
			}
			started = false;
		}
	}
	
	/**
	 * Gets the instance of the CRT running in the node
	 * @return Instance of the CRT running in the node
	 */
	public CrtImpl getCrt()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getCrt()");
		
		return crt;
	}
	
	///////////////////////////////////////////////////////
	
	//RUN METHOD///////////////////////////////////////////
	/**
	 * Overriding the run method of class Thread
	 */
	public void run() 
	{	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.run()");

		terminateThread = false;
		
		while (!terminateThread)
		{	
			while (!started)
			{
				MWMonitor.cfgSetComponentStatus(crt.getCrtRegisteredComponent(), MWMonitor.STATUS_STARTING);
			
				try {
					startPlatform();
					started = true;
					
					try {	
						Thread.sleep(5 * 1000);
					} catch(InterruptedException ie) {				
						ie.printStackTrace();
					}
					getNodePresence().announceNew(nodePresence.getLocalPresenceKey());
					
					break;
				} catch (CrtException crte){
					CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR, 
							"JxtaModule.run() The JXTA module could not be started. It will be tried again", null);			
				}
				
				try {
					Thread.currentThread().sleep(60*1000);
				} catch(InterruptedException ie){
					ie.printStackTrace();
				}
			}
		
		
		
			/*System.out.println(" __________LISTA DE MENSAJES _______");			
			crt.getMessageDispatcher().getNodeList().printStruct();*/
			
			/*
			System.out.println(" __________LISTA DE THREADS BUSCANDO _______");
			Hashtable h = crt.getMessageDispatcher().getSearchingThreads();
			for (Enumeration e=h.keys();e.hasMoreElements();)
			{
				String nodeId = (String)e.nextElement();
				System.out.println("NODEID:" +  nodeId); 
			}
			
			System.out.println(" __________LISTA DE THREADS ESPERANDO _______");
			Hashtable h2 = crt.getMessageDispatcher().getWaitingThreads();
			for (Enumeration e=h2.keys();e.hasMoreElements();)
			{
				Long messageId = (Long)e.nextElement();
				System.out.println("MESSAGEID:" +  messageId); 
			}*/
			
			
			//Si es un CN comprobamos si existen mas CN en la red
			if ((crt.getConstants().getNodeType() == Constants.CENTRAL_NODE) ||					
					(crt.getConstants().getNodeType() == Constants.GATEWAY_NODE))
			{
				Vector temp = new Vector();
				Vector centralNodes = getSuperNodes();							
				
				//Comprobamos si se ha desconectado algun rendezvous
				Hashtable storedGateways = crt.getNodeIdentifierSolver().getGatewayNodes();
				for (Enumeration e=storedGateways.keys();e.hasMoreElements();)
				{
					String centralNode = (String)e.nextElement();
					//System.out.println("CENTRAL NODE: " + centralNode);
					if (centralNode.equals(crt.getOwnNodeId()))
						continue;
					if (!centralNodes.contains(centralNode))
					{
						PresenceKey presenceToBeRemoved = new PresenceKey();
						presenceToBeRemoved.setPresenceName(centralNode);
						presenceToBeRemoved.setNodeType(Constants.CENTRAL_NODE);
						Iterator it = crt.getNodeIdentifierSolver().getJxtaConnectedPeers().entrySet().iterator();
						while (it.hasNext()) {
							Map.Entry entry = (Map.Entry)it.next();
							if (((String)entry.getValue()).equals(centralNode))
							{
								presenceToBeRemoved.setPresenceNodeID((String)entry.getKey());
								break;
							}														
						}							
						nodePresence.announceLeave(presenceToBeRemoved);
						//Deberia borrar tb. todos los nodo JXME conectados a ese nodo
					}					
				}
			}
			
			/*try {
	    		System.out.println(crt.getOwnNodeId());
	    		PeerAdvertisement adv 	= null;
	    		Enumeration en			= null;
	    		String peerId2			= null;
	    		en = midasDiscovery.getLocalAdvertisements(DiscoveryService.ADV, null, null);
	    		
	    		if (en != null ) 
	    		{	    			
	    			String ipAddresses = "";
	    			while( en.hasMoreElements() )
	                {   
	    				System.out.println("POR LO MENOS LLEGAMOS A ENTRAR");
	                	//We make this check because sometimes we get RouteAdv or ModuleImplAdv
	                	Object object =  en.nextElement();
	                	System.out.println(object.toString());
	                	if (object.getClass().getName().equals("net.jxta.impl.protocol.RdvAdv"))
	                	{                		
	                			break;              		
	                	}
	                }
	    		}
	    		else
	    			System.out.println("ES NULL");
	    			
	    	} catch (IOException ioe){
	    		ioe.printStackTrace();
	    	}*/
			
			/*String peers = "";
			for (Enumeration e = crt.getNodeIdentifierSolver().getNodeIdToIpConnectedPeers().keys(); e.hasMoreElements(); )
			{
				String name = (String)e.nextElement();					
				String ip 	= (String)crt.getNodeIdentifierSolver().getIPAddress(name);
				peers += "\nName: " + name + " IP: " + ip;					
		    }
			CfgLogging.logEvent(CfgLogging.LOG_INFO, "CRT.JxtaBaseModule", 0,
					"run(). TABLE WITH CONNECTED PEERS MIDAS: " + peers);
			peers = "";
			
			for (Enumeration e = crt.getNetworkManager().getPresenceSubscriptions().keys(); e.hasMoreElements(); ) 				
				peers += "\n" + (String)e.nextElement();					
			CfgLogging.logEvent(CfgLogging.LOG_INFO, "CRT.JxtaBaseModule", 0, 
					"run(). TABLE WITH PRESENCE SUBSCRIPTIONS: " + peers);
			*/			
			
			try {	
				Thread.sleep(20 * 1000);
			} catch(InterruptedException ie) {				
				ie.printStackTrace();
			}			
		} 		
	}
	///////////////////////////////////////////////////////
			
	
	//CACHE RELATED FUNCTIONS//////////////////////////////
	/**
	 * Clears the local cache
	 * 
	 * @param ds Discovery service of the JXTA Peer Group we are cleaning the local cache
	 * @throws CrtException If the local cache can not be deleted
	 */
	protected void clearLocalCache(DiscoveryService ds) throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.clearLocalCache(DiscoveryService)");			
		
		try
		{
			if (ds != null)
			{				
				//Deleting generic advertisements			
				Enumeration en1 = ds.getLocalAdvertisements(ds.ADV, null, null);
				while(en1.hasMoreElements())
				{
					
					Advertisement adv = (Advertisement )en1.nextElement();							
					ds.flushAdvertisement(adv);
				}
				
				//Deleting peers in cache		
				Enumeration en2 = ds.getLocalAdvertisements(ds.PEER,null,null);
				while(en2.hasMoreElements())
				{
					PeerAdvertisement peerAdv = (PeerAdvertisement)en2.nextElement();			
					ds.flushAdvertisement(peerAdv);
				}
				
				//Deleting groups in cache		
				Enumeration en3 = ds.getLocalAdvertisements(ds.GROUP,null,null);
				while(en3.hasMoreElements())
				{
					PeerGroupAdvertisement groupAdv = (PeerGroupAdvertisement)en3.nextElement();					
					ds.flushAdvertisement(groupAdv);
				}
				
				CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
						"JxtaModule.clearLocalCache(DiscoveryService). Cache is now empty!!!");				
			}			
			else
				CfgError.errorReporting(CfgError.ERR_INFO, Logger.COMPONENT_CRT, CfgError.SEV_INFORMAL, 
				"JxtaModule.clearLocalCache(DiscoveryService). The Discovery Service is null!", null);

		} catch(IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR, 
					"JxtaModule.clearLocalCache(DiscoveryService). An I/O has ocurred cleaning " +
					"the local cache: '" + ioe.getMessage() + "'", null);
			throw new CrtException();
		}
	}
	
	/**
	 * Clears the local cache related to a MIDAS node
	 * 
	 * @param ds Discovery service of the JXTA Peer Group we are cleaning the local cache
	 * @param peerId MIDAS node identifier
	 * @throws CrtException If the local cache can not be deleted
	 */
	protected void clearLocalCache(DiscoveryService ds, String nodeId) throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.clearLocalCache(DiscoveryService, " + nodeId + ")");		
		
		try
		{
			if (ds != null)
			{				
				//Deleting generic advertisements			
				Enumeration en1 = ds.getLocalAdvertisements(ds.ADV, "Name", nodeId);
				while(en1.hasMoreElements())
				{
					
					Advertisement adv = (Advertisement )en1.nextElement();
					ds.flushAdvertisement(adv);
				}
				
				//Deleting peers in cache		
				Enumeration en2 = ds.getLocalAdvertisements(ds.PEER,"Name", nodeId);
				while(en2.hasMoreElements())
				{
					PeerAdvertisement peerAdv = (PeerAdvertisement)en2.nextElement();
					ds.flushAdvertisement(peerAdv);
				}
				
				CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
				"JxtaModule.clearLocalCache(DiscoveryService, " + nodeId + "). Cache is now empty!!!");				
			}			
			else
				CfgError.errorReporting(CfgError.ERR_INFO, Logger.COMPONENT_CRT, CfgError.SEV_INFORMAL, 
				"JxtaModule.clearLocalCache(DiscoveryService, " + nodeId + "). The Discovery Service is null!", null);

		} catch(IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR, 
					"JxtaModule.clearLocalCache(DiscoveryService, " + nodeId + "). An I/O has ocurred cleaning " +
					"the local cache: '" + ioe.getMessage() + "'", null);
			throw new CrtException();
		}
	}
	
	/**
	 * Clears the JXTA cache files
	 * 
	 * @param rootDir Root folder to start cleaning
	 */
	public void clearCache(final File rootDir) 
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.clearCache(File)");
		
		try 
		{
			if (rootDir.exists()) 
			{
				File[] list = rootDir.listFiles();
				for (int i=0; i<list.length; i++) 
				{
					if (list[i].isDirectory())
						clearCache(list[i]);
					else
						list[i].delete();               
				}
			}
	        rootDir.delete();
	        CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgError.SEV_INFORMAL,
	        		"JxtaModule.clearCache(File). Cache component " + rootDir.toString() + " cleared.");
		} catch (Throwable t) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR,
					"JxtaModule.clearCache(File). Unable to clear " + rootDir.toString() + ": '" +
					t.getMessage() + "'", null);			
		}
	}
	///////////////////////////////////////////////////////
	
	
	//JXTA RELATED FUNCTIOS////////////////////////////////
	/**
	 * Container for Rendezvous Service events. The source of the event is the
	 * rendezvous service generating the event
	 *  
	 * @param event Rendezvous event
	 */
	public synchronized void rendezvousEvent(RendezvousEvent event)
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.rendezvousEvent(RendezvousEvent)");			
		
		/*SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
		Date date = new Date();*/
				
		if ((crt.getConstants().getNodeType() == Constants.CENTRAL_NODE) ||
				(crt.getConstants().getNodeType() == Constants.GATEWAY_NODE))
		{
			String rendezVousServiceImpl = getCentralNodeEventSource(event);
			//Check if the even matches with a MIDAS rendezvous
		    if (rendezVousServiceImpl.equals(midasRendezvousServiceID))
		    {	
		    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
		    			"JxtaModule.rendezvousEvent(RendezvousEvent). RDV EVENT " + event.toString());
		    	//System.out.println("TIME: " + formatter.format(date));				
				if( event.getType() == RendezvousEvent.RDVCONNECT)
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
			    			"JxtaModule.rendezvousEvent(RendezvousEvent). Connected to a rendezvous");
				else if( event.getType() == RendezvousEvent.RDVDISCONNECT)
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
			    			"JxtaModule.rendezvousEvent(RendezvousEvent). Disconnected from a rendezvous");
				
				else if( event.getType() == RendezvousEvent.CLIENTCONNECT)
			    {	
			    	/*if ((String)crt.getNodeIdentifierSolver().getNodeId(event.getPeerID().toString()) == null)
			    	{	
			    		try {
				    		String nodeName = getNetworkAddress(event.getPeerID(), midasDiscovery);				    		
				    		
				    		Thread.sleep(1000);				    		
				    		
				    		//If there is any application/component interested in the
				    		//presence of this node	
				    		 crt.getNetworkManager().notifyPresence(nodeName, true);				    						    		 
				    		 
			    		} catch (InterruptedException ie){			    			
			    			ie.printStackTrace();
			    		}catch (CrtException crte) {}
			    	}*/
			    	
			    }
			    
				else if( event.getType() == RendezvousEvent.CLIENTRECONNECT)
				{	
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
			    			"JxtaModule.rendezvousEvent(RendezvousEvent). Reconnected to a rendezvous");					
				}
				
				else if( event.getType() == RendezvousEvent.CLIENTFAILED || 
			    		event.getType() == RendezvousEvent.CLIENTDISCONNECT)
			    {
			    	/*String nodeName = crt.getNodeIdentifierSolver().remove(event.getPeer());
				    if (nodeName != null)
				    {				    	
				    	//If there is any application/component interested in the
			    		//presence of this node	
				    	try { 
				    		crt.getNetworkManager().notifyPresence(nodeName, false);
			    		} catch (CrtException crte) {}			    		
				    }*/
				}
		    }
		}
		else
		{
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
	    			"JxtaModule.rendezvousEvent(RendezvousEvent). RDV EVENT " + event.toString());
			
		    if(event.getType() == RendezvousEvent.RDVCONNECT)
		    {	
		    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
		    			"JxtaModule.rendezvousEvent(RendezvousEvent). Connected to a rendezvous");
		    	
		    	centralNodeJXTAId 	= event.getPeerID().toString().substring(9);				    	
		    	notify();
		    }
		    
		    else if(event.getType() == RendezvousEvent.RDVRECONNECT)
		    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
		    			"JxtaModule.rendezvousEvent(RendezvousEvent). Reconnected to a rendezvous");    				    			   
		    
		    else if( event.getType() == RendezvousEvent.RDVFAILED || 
		    		event.getType() == RendezvousEvent.RDVDISCONNECT)
		    {
		    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
		    			"JxtaModule.rendezvousEvent(RendezvousEvent). Disconnected from a rendezvous");
		    		//crt.getNodeIdentifierSolver().stopNodeIdentifierSolver();
		    }
			/*String  rendezVousServiceImpl = getCentralNodeEventSource(event);			
			if (midas != null)
			{
		    //Check if the even matches with a MIDAS rendezvous
			    if (rendezVousServiceImpl.equals(getMidasRendezvousID()))
			    {	
			    	//System.out.println("TIME: " + formatter.format(date));
			    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
			    			"JxtaModule.rendezvousEvent(RendezvousEvent). RDV EVENT " + event.toString());
					
				    if(event.getType() == RendezvousEvent.RDVCONNECT)
				    {	
				    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
				    			"JxtaModule.rendezvousEvent(RendezvousEvent). Connected to a rendezvous");
				    	
				    	centralNodeJXTAId 	= event.getPeerID().toString().substring(9);				    	
				    	notify();
				    }
				    
				    else if(event.getType() == RendezvousEvent.RDVRECONNECT)
				    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
				    			"JxtaModule.rendezvousEvent(RendezvousEvent). Reconnected to a rendezvous");    				    			   
				    
				    else if( event.getType() == RendezvousEvent.RDVFAILED || 
				    		event.getType() == RendezvousEvent.RDVDISCONNECT)
				    {
				    	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
				    			"JxtaModule.rendezvousEvent(RendezvousEvent). Disconnected from a rendezvous");
				    		//crt.getNodeIdentifierSolver().stopNodeIdentifierSolver();
				    }
			    }		    
			}	    
		    else
		    {
		    	if(event.getType() == RendezvousEvent.RDVCONNECT)
			    {
		    		CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
			    			"JxtaModule.rendezvousEvent(RendezvousEvent).Connected to a rendezvous for NetPeerGroup");
			    	notify();
			    }
		    }*/
		}	    
	}	
	
	/**
     * Allows to build a hashtable to map JXTA unique identifiers to unique
     * MIDAS node identifiers 
     * 
     * @param peerId JXTA unique identifier
     * @param ds Discovery service of the JXTA Peer Group where to find the
     * 			JXTA identifier
     * @return The MIDAS node identifier
     */
	protected String getNetworkAddress (ID peerId, DiscoveryService ds) 
	{      
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG,
				"JxtaModule.getNetworkAddress(ID, DiscoveryService)");
		
        String idstring  	= peerId.toString();                  
        String name 		= null;
        String ipAddresses  = "";
        if (crt.getNodeIdentifierSolver().getJxtaConnectedPeers().containsKey(idstring))
        	name = ((String)crt.getNodeIdentifierSolver().getNodeId(idstring));
        
        if( null != name ) {        	
            return name;
        }
        
        try {
            Enumeration res;   
         
            if( peerId instanceof PeerID ) 
            {   
            	try {
            		//System.out.println("IDSTRING: " + idstring);
    	        	res = ds.getLocalAdvertisements(DiscoveryService.PEER, "PID", null);
    	        	    	            		        	
    	        	Advertisement peerAdv;
    	    	    while (res.hasMoreElements()) 
    	    	    {
    	    	    	peerAdv = (Advertisement) res.nextElement();
    	    	    	//System.out.println(peerAdv);
    	    	    	//name = peerAdv.getName();
    	    	    }
            	} catch (IOException ioe){ioe.printStackTrace();}
            	
                //res = ds.getLocalAdvertisements( DiscoveryService.PEER, "PID", idstring );
            	//This filter does not work properly
            	/*res = ds.getLocalAdvertisements( DiscoveryService.PEER, "PID", null );              	            		
                while( res.hasMoreElements() )
                {                	
                	//We make this check because sometimes we get RouteAdv or ModuleImplAdv
                	Object object =  res.nextElement();
                	
                	if (object.getClass().getName().equals("net.jxta.impl.protocol.PeerAdv"))
                	{                		
                		if (((PeerAdvertisement)object).getPeerID().toString().equals(idstring))
                		{
                			System.out.println(((PeerAdvertisement)object).toString());
                			name = ((PeerAdvertisement)object).getName();                			
            				Element doc			= ((PeerAdvertisement)object).getServiceParam(PeerGroup.endpointClassID);            				
            				Enumeration children = doc.getChildren("jxta:RA");   
            				if (children.hasMoreElements())
            				{                					
            					doc 		= (Element)children.nextElement();
            					children 	= doc.getChildren("Dst");
            					if (children.hasMoreElements())
                				{            						
            						doc 		= (Element)children.nextElement();
                					children 	= doc.getChildren("jxta:APA");                					
                					if (children.hasMoreElements())
                    				{            						
                						doc 		= (Element)children.nextElement();
                    					children 	= doc.getChildren("EA");
	                					while (children.hasMoreElements())
	                    				{                						
	                    					doc 				= (Element)children.nextElement();
	                    					String ipAddress 	= doc.getValue().toString();
	                    					if (ipAddress.startsWith("tcp://"))	                    				
	                    						ipAddresses += ipAddress.split(":", 2)[1].substring(2) + ";";                        			
	                    				}
                    				}
                				}
                			}                			               			                	
                			break;
                		}                		
                	}
                }*/
            } 
            else if( peerId instanceof PeerGroupID ) 
            {            	
                res = ds.getLocalAdvertisements( DiscoveryService.GROUP, "GID", idstring );
                
                while( res.hasMoreElements() )
                {                	
                	Object object =  res.nextElement();
                	if (object.getClass().getName().equals("net.jxta.impl.protocol.PeerGroupAdv"))
                	{                		
                		name = ((PeerGroupAdvertisement)object).getName();                		
                		break;
                	}
                }
            }
        }  catch( IOException ioe ) {
        	ioe.printStackTrace();
        }
        
        /*if( null != name )          
        	crt.getNodeIdentifierSolver().put(idstring, name, ipAddresses);
        else
            name = "[unknown]";
        */
        return name;
    }	
	
	/**
	 * Searchs a node in the MIDAS nertwork
	 * 
	 * @param nodeId MIDAS node identifier of the node
	 * @return JXTA identifier of the node if it finds it; null otherwise
	 * @throws CrtException If something fails
	 */
	public String seachNode(String nodeId) throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.seachNode(" + nodeId + ")");
		
		//First, we search in the local cache
		PeerAdvertisement adv 	= null;
		Enumeration en			= null;
		String peerId			= null;
		
		try {			
			en 	= midasDiscovery.getLocalAdvertisements(
					   	DiscoveryService.PEER, "Name", nodeId);
		} catch (IOException ioe) {
			throw new CrtException();
		}
		
		if (en != null ) 
		{
			while (en.hasMoreElements()) {
				adv = (PeerAdvertisement) en.nextElement();
				
				if (adv.getName().equals(nodeId))
				{
					//System.out.println(adv.toString());
					peerId = adv.getPeerID().toString();					
					//System.out.println("LO TENGO EN LOCAL:::::::");
					break;
				}
				
			}
		}
		//clearLocalCache(netPGDiscoveryService);
		if (peerId == null)
		{
			SearchThread temp = new SearchThread(crt.getMessageDispatcher(), nodeId);
			temp.start();			
			crt.getMessageDispatcher().getSearchingThreads().put(nodeId, temp);
					midasDiscovery.getRemoteAdvertisements(
					//"urn:jxta:" + centralNodeJXTAId, DiscoveryService.PEER, "Name", nodeId, 5, temp);
							null, DiscoveryService.PEER, "Name", nodeId, 5, temp);		
		}
		
		return peerId;
	}
	
	/**
	 * Gets all the nodes playing the role of Central Node or Gateway Node
	 * 
	 * @return A vector storing the names of all nodes playing the role of Central Node 
	 * 			or Gateway Node
	 */
	public Vector getSuperNodes()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, "JxtaModule.getSuperNodes()");
		
		Vector rendezvousNames = new Vector();
		RdvAdvertisement rdvAd = null;
		Vector vector = midas.getRendezVousService().getLocalWalkView();
		for (Enumeration e=vector.elements(); e.hasMoreElements();)
		{
			rdvAd = (RdvAdvertisement)e.nextElement();
			rendezvousNames.add(rdvAd.getName());
		}
		return rendezvousNames;
	}
	///////////////////////////////////////////////////////
	
	//MESSAGE RELATED FUNCTIONS////////////////////////////
	/**
	 * Sends the specified message 
	 * 
	 * @param peerId JXTA identifier of the destination node
	 * @param ipMessage IPMessage storing the necessary information to send the message
	 */	
	public void sendMessage(String peerId, IPMessage ipMessage) throws CrtException
	{	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG,  
				"JxtaModule.sendMessage(" + peerId + ", IPMessage)");

		EndpointAddress epa = new EndpointAddress("jxta", peerId.substring(9), Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());					
		if (epa == null)
		{
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_WARNING,  
					"JxtaModule.sendMessage(" + peerId + ", IPMessage). Failed to get the EndPointAddress " +
					"of the destination node", null);
			seachNode(ipMessage.getDestinationNodeId());
			throw new CrtException();
		}
		else
		{
			Messenger messenger = midas.getEndpointService().getMessenger(epa, null);
			if (messenger == null)
			{
				CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_WARNING,
						"JxtaModule.sendMessage(" + peerId + ", IPMessage). Failed to get the Messenger " +
						"of the destination node", null);
				seachNode(ipMessage.getDestinationNodeId());
				throw new CrtException();
			}
			else
			{
				Message message = new Message();					
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_TYPE, ipMessage.getMessageType(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.JXTA_ID, midas.getPeerID().toString(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_NODE, ipMessage.getSourceNodeId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_NODE, ipMessage.getDestinationNodeId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_APP, ipMessage.getSourceUserId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_APP, ipMessage.getDestinationUserId(), null));				
				//message.addMessageElement(Constants.MIDAS,new StringMessageElement("DATA", data, null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_ID, ipMessage.getMessageId().toString(), null));				
				
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.TOTAL_LENGTH, Integer.toString(ipMessage.getTotalLength()), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_MESSAGES, Integer.toString(ipMessage.getNumMessages()), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_ORDER, Integer.toString(ipMessage.getNumOrder()), null));
				
				if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST))
				{
				if (ipMessage.getConfirmation())
					message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("1"), null));
				else
					message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("0"), null));
				}
				if (ipMessage.getFinalDestinationNodeId() != null)					
					message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.FINAL_DST_NODE, ipMessage.getFinalDestinationNodeId(), null));
					
				message.addMessageElement(Constants.MIDAS,new ByteArrayMessageElement(Constants.DATA, null, ipMessage.getMessageContent(), null));								
				
				try {
					//System.out.println("MANDO MENSAJE: " + ipMessage.getMessageId());
					messenger.sendMessage(message, Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());					
					/*if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST) && ipMessage.getConfirmation() == true
							&& ipMessage.getSourceNodeId().equals(crt.getOwnNodeId()))
					{
						WaitingThread wt = new WaitingThread(crt.getMessageDispatcher(), ipMessage.getDestinationNodeId(), ipMessage.getMessageId());
						wt.start();
						crt.getMessageDispatcher().getWaitingThreads().put(ipMessage.getMessageId(), wt);
					}*/
					messenger.flush();
					messenger.close();
				} catch (IOException ioe) {
					CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR,  
							"JxtaModule.sendMessage(" + peerId + ", IPMessage). An error ocurred sending a message: '" +
							ioe.getMessage() + "'", null);
					clearLocalCache(midasDiscovery, ipMessage.getDestinationNodeId());
					throw new CrtException();
				}
			}
		}
	}
	
	public void sendMessage(String peerId, IPMessage ipMessage, int offset, int length) throws CrtException
	{	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.sendMessage(" + peerId + ", IPMessage, " + offset +  ", " + length + ")");							
		EndpointAddress epa = new EndpointAddress("jxta", peerId.substring(9), Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());					
		if (epa == null)
		{
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_WARNING,  
					"JxtaModule.sendMessage(" + peerId + ", IPMessage, " + offset +  ", " + length + "). Failed to get the EndPointAddress " +
					"of the destination node", null);
			if (!crt.getMessageDispatcher().getNodeList().getStatus(ipMessage.getDestinationNodeId()))
			{
				crt.getMessageDispatcher().getNodeList().setStatus(ipMessage.getDestinationNodeId(), true);
				seachNode(ipMessage.getDestinationNodeId());
			}
			throw new CrtException();
		}
		else
		{
			Messenger messenger = midas.getEndpointService().getMessenger(epa, null);
			if (messenger == null)
			{
				CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_WARNING,  
						"JxtaModule.sendMessage(" + peerId + ", IPMessage, " + offset +  ", " + length + "). Failed to get the Messenger " +
						"of the destination node", null);
				if (!crt.getMessageDispatcher().getNodeList().getStatus(ipMessage.getDestinationNodeId()))
				{
					crt.getMessageDispatcher().getNodeList().setStatus(ipMessage.getDestinationNodeId(), true);
					seachNode(ipMessage.getDestinationNodeId());
				}
				throw new CrtException();
			}
			else
			{
				Message message = new Message();					
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_TYPE, ipMessage.getMessageType(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.JXTA_ID, midas.getPeerID().toString(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_NODE, ipMessage.getSourceNodeId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_NODE, ipMessage.getDestinationNodeId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_APP, ipMessage.getSourceUserId(), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_APP, ipMessage.getDestinationUserId(), null));				
				//message.addMessageElement(Constants.MIDAS,new StringMessageElement("DATA", data, null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_ID, ipMessage.getMessageId().toString(), null));				
				
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.TOTAL_LENGTH, Integer.toString(ipMessage.getTotalLength()), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_MESSAGES, Integer.toString(ipMessage.getNumMessages()), null));
				message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_ORDER, Integer.toString(ipMessage.getNumOrder()), null));
				
				if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST))
				{
					if (ipMessage.getConfirmation()&& ipMessage.getNumOrder() == ipMessage.getNumMessages())
						message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("1"), null));
					else
						message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("0"), null));
				}
				if (ipMessage.getFinalDestinationNodeId() != null)					
					message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.FINAL_DST_NODE, ipMessage.getFinalDestinationNodeId(), null));
					
				message.addMessageElement(Constants.MIDAS,new ByteArrayMessageElement(Constants.DATA, null, ipMessage.getMessageContent(), offset, length, null));								
				
				try {
					messenger.sendMessage(message, Constants.MESSAGE_SERVICE, midas.getPeerGroupID().toString());
					
					CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
							"JxtaModule.sendMessage(" + peerId + ", IPMessage, " + offset +  ", " + length + "). MESSAGE SENT: " + ipMessage.msgToString());
					/*if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST) && ipMessage.getConfirmation()
							&& ipMessage.getSourceNodeId().equals(crt.getOwnNodeId()) 
							&& ipMessage.getNumOrder() == ipMessage.getNumMessages())
					{
						WaitingThread wt = new WaitingThread(crt.getMessageDispatcher(), ipMessage.getDestinationNodeId(), ipMessage.getMessageId());
						wt.start();
						crt.getMessageDispatcher().getWaitingThreads().put(ipMessage.getMessageId(), wt);
					}*/
					messenger.flush();
					messenger.close();
					//MUY IMPORTANTE: NO INCLUIR ESTE CLEAR PORQUE SI NO SE PIERDEN MUCHOS MENSAJES
					//message.clear();
				} catch (IOException ioe) {
					CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR,  
							"JxtaModule.sendMessage(" + peerId + ", IPMessage, " + offset +  ", " + length + "). An error ocurred sending a message: '" +
							ioe.getMessage() + "'", null);
					clearLocalCache(midasDiscovery, ipMessage.getDestinationNodeId());
					throw new CrtException();
				}
			}
		}
	}
	
	public void forwardMessage(IPMessage ipMessage) throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG,  
				"JxtaModule.forwardMessage(IPMessage)");
		
		//First, we search in the local cache
		PipeAdv adv 	= null;
		Enumeration en	= null;				
		try {			
			en 	= midasDiscovery.getLocalAdvertisements(
					   	DiscoveryService.ADV, "Name", ipMessage.getDestinationNodeId() + "Pipe");
			
			while (en.hasMoreElements())
			{
				adv = (PipeAdv)en.nextElement();
				if (adv != null)
					break;
								
			}
			if (adv != null)
			{
				OutputPipe outputPipe = midas.getPipeService().createOutputPipe(adv, 1);
				if (outputPipe != null)
				{
					Message msg = new Message();					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_TYPE, ipMessage.getMessageType(), null));				
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_NODE, ipMessage.getSourceNodeId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_NODE, ipMessage.getDestinationNodeId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_APP, ipMessage.getSourceUserId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_APP, ipMessage.getDestinationUserId(), null));					
					if (ipMessage.getMessageId() != null)					
						msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_ID, ipMessage.getMessageId().toString(), null));
					
					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.TOTAL_LENGTH, Integer.toString(ipMessage.getTotalLength()), null));
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_MESSAGES, Integer.toString(ipMessage.getNumMessages()), null));
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_ORDER, Integer.toString(ipMessage.getNumOrder()), null));
					
					if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST))
					{
						if (ipMessage.getConfirmation() &&
								ipMessage.getNumOrder() == ipMessage.getNumMessages())
							msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("1"), null));						
						else
							msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("0"), null));
					}					
					
					msg.addMessageElement(Constants.MIDAS,new ByteArrayMessageElement(Constants.DATA, null, ipMessage.getMessageContent(), null));									
					
					//System.out.println("MENSAJE ANTES DE MANDAR(1): " + ipMessage.msgToString());
					//send the message
					boolean sent = false;
					long actualTime = System.currentTimeMillis();
					do {
						sent = outputPipe.send(msg);
						try {
							Thread.sleep(200);
						} catch (InterruptedException ie){}
					} while (!sent && System.currentTimeMillis() <= (actualTime + 3000));
					
					if (!sent)
						CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_INFORMAL, 
								"JxtaModule.forwardMessage(IPMessage). Message COULD NOT BE SENT", null);
					else
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
								"JxtaModule.forwardMessage(IPMessage). Message sent. MESSAGE SENT: " + ipMessage.msgToString() + " TO PIPE: " + adv.getPipeID().toString());					
					outputPipe.close();
					
					/*outputPipe.send(msg);
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
							"JxtaModule.forwardMessage(IPMessage). Message sent. MESSAGE SENT: " + ipMessage.msgToString() + " AL PIPE: " + adv.getPipeID().toString());
					outputPipe.close();*/
				}				
				/*try {
					synchronized (outputPipeLock) {
						outputPipeLock.wait(5000);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}*/
			}
			
		} catch (IOException ioe) {
			throw new CrtException();
		}
	}
	
	public void forwardMessage(IPMessage ipMessage, int offset, int length) throws CrtException
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.forwardMessage(IPMessage, " + offset +  ", " + length + ")");
		
		//First, we search in the local cache
		PipeAdv adv 	= null;
		Enumeration en	= null;				
		try {			
			en 	= midasDiscovery.getLocalAdvertisements(
					   	DiscoveryService.ADV, "Name", ipMessage.getDestinationNodeId() + "Pipe");
			
			while (en.hasMoreElements())
			{
				adv = (PipeAdv)en.nextElement();
				if (adv != null)
					break;
								
			}
			if (adv != null)
			{
				OutputPipe outputPipe = midas.getPipeService().createOutputPipe(adv, 1);
				if (outputPipe != null)
				{
					Message msg = new Message();					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_TYPE, ipMessage.getMessageType(), null));				
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_NODE, ipMessage.getSourceNodeId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_NODE, ipMessage.getDestinationNodeId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_APP, ipMessage.getSourceUserId(), null));					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_APP, ipMessage.getDestinationUserId(), null));					
					if (ipMessage.getMessageId() != null)					
						msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_ID, ipMessage.getMessageId().toString(), null));
					
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.TOTAL_LENGTH, Integer.toString(ipMessage.getTotalLength()), null));
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_MESSAGES, Integer.toString(ipMessage.getNumMessages()), null));
					msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.NUM_ORDER, Integer.toString(ipMessage.getNumOrder()), null));
					
					if (ipMessage.getMessageType().equals(Constants.IP_MESSAGE_REQUEST))
					{
						if (ipMessage.getConfirmation() && 
								ipMessage.getNumOrder() == ipMessage.getNumMessages())
							msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("1"), null));						
						else
							msg.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.CONFIRMATION, new String("0"), null));
					}					
														
					msg.addMessageElement(Constants.MIDAS,new ByteArrayMessageElement(Constants.DATA, null, ipMessage.getMessageContent(), offset, length, null));
					
					//System.out.println("MENSAJE ANTES DE MANDAR: " + ipMessage.msgToString());
					//send the message
					boolean sent = false;
					long actualTime = System.currentTimeMillis();
					do {
						sent = outputPipe.send(msg);
						try {
							Thread.sleep(200);
						} catch (InterruptedException ie){}
					} while (!sent && System.currentTimeMillis() <= (actualTime + 3000));
					
					if (!sent)
						CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_INFORMAL, 
								"JxtaModule.forwardMessage(IPMessage, " + offset +  ", " + length + "). Message COULD NOT BE SENT", null);
					else
					CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
								"JxtaModule.forwardMessage(IPMessage, " + offset +  ", " + length + "). Message sent. MESSAGE SENT: " + ipMessage.msgToString() + " TO PIPE: " + adv.getPipeID().toString());
					//System.out.println("OUTPUTPIPE: " + outputPipe.getName());
					//System.out.println("OUTPUTPIPE: " + outputPipe.getPipeID());
					
					outputPipe.close();
				}				
				/*try {
					synchronized (outputPipeLock) {
						outputPipeLock.wait(5000);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}*/
			}
			//else
			//	System.out.println("::::::::  NO ENCONTRAMOS EL ADVERTISEMENT  ::::::::");
			
		} catch (IOException ioe) {
			throw new CrtException();
		}
	}
	
	/**
	 * Spreads a message to all MIDAS nodes
	 * 
	 * @param ipMessage IPMessage storing the necessary information to propagate
	 *  		the message
	 */
	public void propagateMessage(IPMessage ipMessage) throws CrtException
	{	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.propagateMessage(IPMessage)");			
		
		Message message = new Message();;
		try {								
			message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.MESSAGE_TYPE, Constants.IP_MESSAGE_BROADCAST, null));
			message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.JXTA_ID, midas.getPeerID().toString(), null));
			message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_NODE, ipMessage.getSourceNodeId(), null));			
			message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.SRC_APP, ipMessage.getSourceUserId(), null));
			message.addMessageElement(Constants.MIDAS,new StringMessageElement(Constants.DST_APP, ipMessage.getDestinationUserId(), null));						
            
			message.addMessageElement(Constants.MIDAS,new ByteArrayMessageElement(Constants.DATA, null, ipMessage.getMessageContent(), null));							
			
			midas.getRendezVousService().propagateInGroup(message, Constants.BROADCAST_MESSAGE_SERVICE, midas.getPeerGroupID().toString(), midas.getRendezVousService().DEFAULT_TTL);
			
			//Si es un nodo JXTA no hay problema porque lo reenv�a el CN, pero
			//si es el CN tenemos que mandarlo a todos los nodos JXME 
			//If it is a Central Node, forward the message
			if (crt.getJxtaPlatform().getCentralNodeId() == null)
			{
				ipMessage.setMessageType(Constants.IP_MESSAGE_BROADCAST);
				try {					
					Vector jxmeNodes = crt.getNodeIdentifierSolver().getOwnJXMENodes();							
					for (int i=0; i<jxmeNodes.size(); i++)
					{						
						ipMessage.setDestinationNodeId((String)jxmeNodes.get(i));
						crt.getJxtaPlatform().forwardMessage(ipMessage);
					}
				} catch (CrtException crte){
					crte.printStackTrace();
				}										
			}	
		} catch (IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR, 
					"JxtaModule.propagateMessage((IPMessage). " +
					"An error ocurred propagating a message to all MIDAS nodes: '" +
					ioe.getMessage() + "'", null);
			throw new CrtException();
		}   	
	}
	
	/**
	 * Spreads a message to all MIDAS nodes
	 * 
	 * @param message Message storing the necessary information to propagate
	 *  		the message
	 */
	public void propagateMessage(Message message) throws CrtException
	{	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.propagateMessage(Message)");			
				
		try {																				
			midas.getRendezVousService().propagateInGroup(message, Constants.BROADCAST_MESSAGE_SERVICE, midas.getPeerGroupID().toString(), midas.getRendezVousService().DEFAULT_TTL);					
		} catch (IOException ioe) {
			CfgError.errorReporting(CfgError.ERR_OPER, Logger.COMPONENT_CRT, CfgError.SEV_ERROR, 
					"JxtaModule.propagateMessage(Message). " +
					"An error ocurred propagating a message to all MIDAS nodes: '" +
					ioe.getMessage() + "'", null);
			throw new CrtException();
		}   	
	}
	///////////////////////////////////////////////////////
	
	
	
	//PRESENCE RELATED FUNCTIONS///////////////////////////
	public void bulkNodeAdd(HashMap nodes) 
    {	
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.bulkNodeAdd(HashMap)");			
		
		if (nodes.isEmpty())
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
					"JxtaModule.bulkNodeAdd(). Nodes is empty");			
    	else
    	{
    		CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
					"JxtaModule.bulkNodeAdd(). Nodes for bluk pipe: ");			
			Iterator iter = nodes.values().iterator();
			String nodeName = null;
			String proxyName = null;
            while(iter.hasNext())
            {
            	String node = ((PresenceKey)iter.next()).toString();
            	CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
						"JxtaModule.bulkNodeAdd(). " + node);            	
                StringTokenizer st = new StringTokenizer(node, ",");                
                crt.getNodeIdentifierSolver().put(st.nextToken(), nodeName = st.nextToken(), new Integer(st.nextToken()).intValue(), proxyName = st.nextToken(), "");
                try {
                	crt.getNetworkManager().notifyPresence(nodeName, true);
                } catch (CrtException crte){
                	crte.printStackTrace();
                }
            }			
		}
	}

    public void nodeAdded(PresenceKey presenceKey) 
    {    
    	CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.nodeAdded(PresenceKey)");
    	
		if (presenceKey == null)
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
					"JxtaModule.nodeAdded(PresenceKey): Presence key is null");
		else
		{
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
					"JxtaModule.nodeAdded(PresenceKey). PEER ADDED Info -->" + 
					" \nPeerID:           " + presenceKey.getPresenceNodeID() + 
			        " \nPeerName:        " + presenceKey.getPresenceName() +
			        " \nNodeType:        " + presenceKey.getNodeType() +
		        	" \nProxyName:        " + presenceKey.getProxyName() +
		        	" \nPeerLastChange:   " + presenceKey.getLastChanged());			
			if (!presenceKey.getPresenceName().equals(crt.getOwnNodeId()) &&
					(presenceKey.getNodeType() == Constants.CENTRAL_NODE
					|| presenceKey.getNodeType() == Constants.GATEWAY_NODE) &&
					!crt.getNodeIdentifierSolver().getGatewayNodes().containsKey(presenceKey.getPresenceName()))
				getNodePresence().announceNew(nodePresence.getLocalPresenceKey());			
			try {
				crt.getNodeIdentifierSolver().put(presenceKey.getPresenceNodeID(), presenceKey.getPresenceName(), new Integer(presenceKey.getNodeType()).intValue(), presenceKey.getProxyName(), "");				
				crt.getNetworkManager().notifyPresence(presenceKey.getPresenceName(), true);
			} catch (CrtException crte){
				crte.printStackTrace();
			}
		}
	}
	
	public void nodeRemoved(PresenceKey presenceKey) 
	{		
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.nodeRemoved(PresenceKey)");
		
		if (presenceKey == null)
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL, 
					"JxtaModule.nodeRemoved(PresenceKey): Presence key is null");
		else
		{
			CfgLogging.logEvent(CfgLogging.LOG_INFO, Logger.COMPONENT_CRT, CfgLogging.SEV_INFORMAL,
					"JxtaModule.nodeRemoved()   PEER REMOVED Info -->" + 
					" \nPeerID:           " + presenceKey.getPresenceNodeID() + 
			        " \nPeerName:        " + presenceKey.getPresenceName() +
			        " \nNodeType:        " + presenceKey.getNodeType() +
		        	" \nProxyName:        " + presenceKey.getProxyName() +
		        	" \nPeerLastChange:   " + presenceKey.getLastChanged());
			try {				
				crt.getNodeIdentifierSolver().remove(presenceKey.getPresenceNodeID());
				crt.getNetworkManager().notifyPresence(presenceKey.getPresenceName(), false);
				clearLocalCache(midasDiscovery, presenceKey.getPresenceName());
				clearLocalCache(midasDiscovery, presenceKey.getPresenceName() + "Pipe" );
			} catch (CrtException crte){crte.printStackTrace();}
		}
	}
	
	/**
	 * Gets the NodePresence instance to manage presence
	 * @return The NodePresence instance to manage presence
	 */
	public NodePresence getNodePresence()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.getNodePresence()");
		
		return nodePresence;
	}
	///////////////////////////////////////////////////////
		
	
	/**
	 * Provides information about nodes acting as Central Nodes or Gateway Nodes
	 * @return Vector with the MIDAS node names foy nodes acting as Central Nodes or Gateway Nodes
	 */
	public Vector getRendezvousNodes()
	{
		CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.getRendezvousNodes()");
		
		Vector rendezvousNames = new Vector();
		RdvAdvertisement rdvAd = null;
		Vector vector = midas.getRendezVousService().getLocalWalkView();
		for (Enumeration e=vector.elements(); e.hasMoreElements();)
		{
			rdvAd = (RdvAdvertisement)e.nextElement();
			rendezvousNames.add(rdvAd.getName());
		}
		return rendezvousNames;	
	}
	
	/*public void testingProxyService()
	{
		try {
			ProxyService svr = (ProxyService)midas.lookupService(PeerGroup.proxyClassID);
			HashMap hs = svr.getConnectedNodes();
			Iterator it = hs.keySet().iterator();

			while (it.hasNext()) {
				Map.Entry e = (Map.Entry)it.next();				
				System.out.println(e.getKey() + " " + e.getValue());
			}
				
		} catch (ServiceNotFoundException snfe) {
			snfe.printStackTrace();
		}			
	}*/
	
		
    protected String getMidasRendezvousID()
    {
    	CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.getMidasRendezvousID()");
    	System.out.println("Oj! Oj! Straszne sprawdzamy cyferki niezrozumiale ogromnie w getMidasRendezvousID! " + ((RendezVousServiceInterface)midas.getRendezVousService().getInterface()).toString());
    	return ((RendezVousServiceInterface)midas.getRendezVousService().getInterface()).toString();
    }
    
	/**
	 * Returns the unique identifier of the rendezvous event
	 * 
	 * @param event Rendezvous event
	 * @return The unique identifier of the rendezvous event
	 */
    protected String getCentralNodeEventSource(RendezvousEvent event)
    {
    	CfgLogging.logEvent(CfgLogging.LOG_MCALL, Logger.COMPONENT_CRT, CfgLogging.SEV_DEBUG, 
				"JxtaModule.getCentralNodeEventSource(RendezvousEvent)");
    	System.out.println("Oj! Oj! Straszne sprawdzamy cyferki niezrozumiale ogromnie w getCentralNodeEventSource! " + ((RendezVousServiceInterface) event.getSource()).getInterface().toString());
    	return ((RendezVousServiceInterface) event.getSource()).getInterface().toString();
    }
    
    public void setStarted(boolean started)
	{
		this.started = started;
	}
}